use crate::api::*;
use crate::boot::db;
use crate::boot::err::MyError;
use crate::model::*;
use crate::lib::{util_string};
use actix_session::Session;
use actix_web::{web, Error, HttpResponse, Responder, Result};
use rbs::Value as rbv;
use serde_json::{json, Value};
use std::collections::HashMap;


// 返回前台页面使用的配置参数 struct
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct OptionStruct {
    pub name: Value,
    pub value: Value,
    pub key: Value,
    pub tag: Value,
    pub color: Value,
    pub icon: Value,
}

// 获取用户的登录信息
pub async fn get_member_data(session: Session) -> Result<HttpResponse, MyError> {
    if let Ok(option) = session.get::<MemberBean>(const_val::SESSION_MEMBER_BEAN) {
        if let Some(memeber_bean) = option {
            resp_ok(1, "成功", &memeber_bean)
        } else {
            resp_err(-1, "获取用户登录信息失败！")
        }
    } else {
        resp_err(-1, "获取用户登录信息失败！")
    }
}

// 获取系统配置参数信息
pub async fn get_option_params() -> Result<HttpResponse, MyError> {

    // 执行 sql 语句，并把结果存入 Vec 中，如读取失败则返回错误 MyError::Db 
    let sql = "select * from sys_option_params where status > 0 order by pid desc, sort desc";
    let list = db::RB
        .fetch_decode::<Vec<SysOptionParams>>(sql, vec![])
        .await
        .map_err(|e| MyError::Db(e))?;

    let mut hash_map_key = HashMap::<i32, String>::new();   // 存放 id，和id对应的参数名称
    let mut hash_map_v = HashMap::<i32, Vec<OptionStruct>>::new();  // 存放 pid，和pid下的选项列表
    let mut hash_map = HashMap::<String, Vec<OptionStruct>>::new(); // 存放 参数名及其下选项列表

    // 遍历list，这里需要使用 into_iter() ,转移所有权
    list.into_iter().for_each(|item| {
        let pid = item.pid.unwrap_or(-1);
        let id = item.id.unwrap_or(-1);
        if pid == 0 {
            // 如果 PID == 0，表示该项是参数信息项
            // 则把 其ID和名称存入map

            // 需要修改map，所以需要 get_mut
            match hash_map_key.get_mut(&id) {
                Some(v) => (),
                None => {
                    hash_map_key.insert(id, item.option_key.unwrap_or("".into()));
                }
            }
        } else {
            // 如果 PID != 0 ，则表示该项是参数下的选项
            // 由于此时不知道上级分类的参数名，所以先以上级 id（pid）, 和当前项存入 map

            let bean = OptionStruct {
                name: json!(item.name.unwrap_or("".into())),
                value: json!(item.option_value.unwrap_or(0)),
                key: json!(item.option_key.unwrap_or("".into())),
                tag: json!(item.tag.unwrap_or("".into())),
                color: json!(item.color.unwrap_or("".into())),
                icon: json!(item.icon.unwrap_or("".into())),
            };

            // 需要修改map，所以需要 get_mut
            match hash_map_v.get_mut(&pid) {
                Some(v) => v.push(bean),
                None => {
                    let mut v = Vec::<OptionStruct>::new();
                    v.push(bean);
                    hash_map_v.insert(pid, v);
                }
            }
        }
    });

    // 使用参数名和选项列表组成新的map
    hash_map_v.into_iter().for_each(|item| {
        // 通过 id 从 map 中提取ID对应的参数名
        let key = hash_map_key.entry(item.0).or_insert("None".into());
        // 涉及到map所有权问题，这里 key 只能是 clone。
        hash_map.insert(key.clone(), item.1);
    }); 

    resp_ok(1, "获取信息成功", hash_map)
}

// 修改密码
pub async fn edit_password(session: Session, data: web::Json<Value>) -> Result<HttpResponse, MyError> {
    let old_pas = data["oldPassword"].as_str().unwrap_or("");  // 获取参数，转换失败则赋予 ""
    let new_pas1 = data["newPassword1"].as_str().unwrap_or(""); 
    let new_pas2 = data["newPassword2"].as_str().unwrap_or(""); 

    if !old_pas.is_empty() && !new_pas1.is_empty() && !new_pas2.is_empty() {
        if new_pas1.eq(new_pas2) {
            if let Ok(o) = session.get::<MemberBean>(const_val::SESSION_MEMBER_BEAN) {
                if let Some(member_bean) = o {
                    let sql = "select * from sys_organ where id = ?";
                    let member_list = db::RB.fetch_decode::<Vec<SysOrgan>>(sql, vec![rbv::I32(member_bean.id)]).await.map_err(|e|MyError::Db(e))?;
                    if let Some(member) = member_list.into_iter().next() {
                        let old_pas_md5 = util_string::app_md5(old_pas);
                        if member.password.unwrap_or("".into()) == old_pas_md5 {
                            let new_pas_md5 = util_string::app_md5(new_pas1);
                            let update_sql = "update sys_organ set password = ? where id = ?";
                            let data = db::RB.exec(update_sql, vec![rbv::String(new_pas_md5), rbv::I32(member_bean.id)]).await.map_err(|e|MyError::Db(e))?;
                            log::info!("执行结果：{:?}", &data);
                            if data.rows_affected > 0 {  
                                resp_ok(1, "密码修改成功", "success")
                            } else {
                                resp_err(-1, "密码修改失败")
                            } 
                        } else {
                            resp_err(-1, "原密码错误")
                        }
                    } else {
                        resp_err(-1, "获取当前用户信息失败")
                    } 
                } else {
                    resp_err(-1, "获取登录信息失败")
                } 
            } else {
                resp_err(-1, "获取登录信息失败")
            } 
        } else {
            resp_err(-1, "两次输入的密码不一致！")
        } 
    } else {
        resp_err(-1, "参数丢失")
    } 
}


pub async fn hello2() -> impl Responder {
    HttpResponse::Ok()
        .content_type("text/plain")
        .body(format!("Your name is {}", 232))
}

pub async fn hello3(data: web::Json<Value>) -> Result<HttpResponse, Error> {
    let a = data["xxxxx"].as_str().unwrap_or_else(|| "x");

    log::info!("用户名：{} 密码：{} ", data["phone"].as_str().unwrap(), a);

    for (key, value) in data.as_object().unwrap() {
        log::info!("{} : {}", key, value);
    }

    let list = ggg(&data);
    let s: String = list.join("-");
    log::info!("{}", s);

    Ok(HttpResponse::Ok()
        .content_type("text/plain")
        .body(format!("Your name is {}", data)))
}

fn ggg(data: &Value) -> Vec<String> {
    let mut list: Vec<String> = Vec::new();
    for (key, value) in data.as_object().unwrap() {
        log::info!("{} : {}", key, value);
        list.push(format!("{} = {}", key, value));
    }
    list
}
